#include "JsonPathSquareBracket.h"

#include "Common/StringUtil.h"
#include "JsonPathFilterExpr.h"
#include "JsonPathIndex.h"
#include "Log/Log.h"
#include "Poco/RegularExpression.h"
#include "Poco/StringTokenizer.h"

JsonPathSquareBracket::JsonPathSquareBracket(std::string str)
{
    m_bValid = false;
    while (str[str.size() - 1] == ']' || str[str.size() - 1] == ' ') str.erase(str.size() - 1);
    m_bValid = Tokenization(str);
}

bool JsonPathSquareBracket::IsValid()
{
    return m_bValid;
}

bool JsonPathSquareBracket::Tokenization(std::string str)
{
    Poco::RegularExpression re1(R"(\[\s*\?)");//用它来匹配 [?
    Poco::RegularExpression::Match match;
    re1.match(str, 0, match);
    if (match.length > 0)
    {
        m_eType = JsonPathSquareBracketType_FilterExpr;
        return TokenizationFilterExpr(str.substr(match.offset + match.length));
    }

    Poco::RegularExpression re2(R"(\[\s*\*)");//用它来匹配 [*]
    re2.match(str, 0, match);
    if (match.length > 0)
    {
        m_eType = JsonPathSquareBracketType_Wildcard;
        return true;
    }

    m_eType = JsonPathSquareBracketType_Index;
    return TokenizationIndex(str);
}

bool JsonPathSquareBracket::TokenizationFilterExpr(std::string strExpr)
{
    Poco::RegularExpression re(R"(\([^(]*?\))");//用它来匹配 [?((( @.price>10) || (@.name=="a")) && (@.price>10 || @.name=="a"))]
    Poco::RegularExpression::Match match;
    bool bValid = false;
    do
    {
        int iRe = re.match(strExpr, 0, match);
        if (match.length < 0 || iRe <= 0)
        {
            if (bValid)
            {
                break;
            }
            zlog.SError("%s: tokenization filter expr error: %s\n", __PRETTY_FUNCTION__, strExpr.c_str());
            return false;
        }
        bValid = true;
        std::string strSubExpr = strExpr.substr(match.offset, match.length);
        strSubExpr.erase(0, strSubExpr.find('(') + 1);
        strSubExpr.erase(strSubExpr.find(')'));
        strExpr.erase(match.offset, match.length);

        JsonPathFilterExpr jpfe("", "");
        bool hasAnd = strSubExpr.find("&&") != std::string::npos;
        bool hasOr = strSubExpr.find("||") != std::string::npos;

        if (hasAnd || hasOr)
        {
            std::string str;
            Poco::StringTokenizer st(strSubExpr, "||", Poco::StringTokenizer::TOK_IGNORE_EMPTY | Poco::StringTokenizer::TOK_TRIM);
            for (size_t j = 0; j < st.count(); j++)
            {
                // 处理次级运算符
                const char* secondaryOp = (st[j].find("&&") != std::string::npos) ? "&&" : nullptr;
                if (secondaryOp)
                {
                    Poco::StringTokenizer sub_st(st[j], secondaryOp, Poco::StringTokenizer::TOK_IGNORE_EMPTY | Poco::StringTokenizer::TOK_TRIM);
                    JsonPathFilterExpr* sub_expr = new JsonPathFilterExpr("", "");

                    std::string str2;
                    for (size_t k = 0; k < sub_st.count(); k++)
                    {
                        JsonPathFilterExpr tmp = GetAndDeleteJPFE(sub_st[k]);
                        if (tmp.m_strUUID.empty())
                        {
                            sub_expr->PushSubExpr(new JsonPathFilterExpr(str2, sub_st[k]));
                        }
                        else
                        {
                            JsonPathFilterExpr* p = new JsonPathFilterExpr(tmp);
                            p->m_stData.m_strLeftLogic = str2;
                            sub_expr->PushSubExpr(p);
                        }
                        str2 = secondaryOp;
                    }
                    sub_expr->m_stData.m_strLeftLogic = str;
                    jpfe.PushSubExpr(sub_expr);
                }
                else
                {
                    JsonPathFilterExpr tmp = GetAndDeleteJPFE(st[j]);
                    if (tmp.m_strUUID.empty())
                    {
                        jpfe.PushSubExpr(new JsonPathFilterExpr(str, st[j]));
                    }
                    else
                    {
                        JsonPathFilterExpr* p = new JsonPathFilterExpr();
                        *p = tmp;
                        p->m_stData.m_strLeftLogic = str;
                        jpfe.PushSubExpr(p);
                    }
                }
                str = "||";
            }
        }
        else
        {
            jpfe = JsonPathFilterExpr("", strSubExpr);
        }

        strExpr.insert(match.offset, jpfe.m_strUUID);
        m_vecFilterExpr.push_back(jpfe);
    } while (1);

    if (m_vecFilterExpr.size() != 1)
    {
        zlog.SError("%s: tokenization filter expr error: %s\n", __PRETTY_FUNCTION__, strExpr.c_str());
        return false;
    }
    return true;
}

bool JsonPathSquareBracket::TokenizationIndex(std::string strIndex)
{
    while (strIndex[0] == '[' || strIndex[0] == ' ') strIndex.erase(0, 1);
    bool hasComma = strIndex.find(',') != std::string::npos;
    bool hasColon = strIndex.find(':') != std::string::npos;
    int iTmp;
    if (hasComma || hasColon)
    {
        Poco::StringTokenizer st(strIndex, ",", Poco::StringTokenizer::TOK_IGNORE_EMPTY | Poco::StringTokenizer::TOK_TRIM);
        for (size_t j = 0; j < st.count(); j++)
        {
            // 处理次级运算符
            const char* secondaryOp = (st[j].find(":") != std::string::npos) ? ":" : nullptr;
            if (secondaryOp)
            {
                while (st[j][0] == ' ') st[j].erase(0, 1);
                RangeIndex ri;
                int iIndex = st[j].find(':');
                if (iIndex == 0) ri.m_iStart = 0;
                else
                {
                    if (StringUtil::String2Int(st[j].substr(0, iIndex), iTmp))
                    {
                        ri.m_iStart = iTmp;
                    }
                    else
                    {
                        zlog.SError("%s: tokenization index error: %s\n", __PRETTY_FUNCTION__, strIndex.c_str());
                        return false;
                    }
                }
                st[j].erase(0, iIndex + 1);

                if (st[j].empty())
                {
                    ri.m_iEnd = -1;
                    m_jpiIndex.m_vectRangeIndex.push_back(ri);
                    continue;
                }

                iIndex = st[j].find(':');
                if (iIndex == 0)
                {
                    ri.m_iEnd = -1;
                }
                else if (iIndex == std::string::npos)
                {
                    if (StringUtil::String2Int(st[j], iTmp))
                    {
                        ri.m_iEnd = iTmp;
                    }
                    else
                    {
                        zlog.SError("%s: tokenization index error: %s\n", __PRETTY_FUNCTION__, strIndex.c_str());
                        return false;
                    }
                }
                else
                {
                    if (StringUtil::String2Int(st[j].substr(0, iIndex), iTmp))
                    {
                        ri.m_iEnd = iTmp;
                    }
                    else
                    {
                        zlog.SError("%s: tokenization index error: %s\n", __PRETTY_FUNCTION__, strIndex.c_str());
                        return false;
                    }
                    st[j].erase(0, iIndex + 1);
                    if (StringUtil::String2Int(st[j], iTmp))
                    {
                        ri.m_iStep = iTmp;
                    }
                    else
                    {
                        zlog.SError("%s: tokenization index error: %s\n", __PRETTY_FUNCTION__, strIndex.c_str());
                        return false;
                    }
                }
                ri.m_bEnd = true;
                m_jpiIndex.m_vectRangeIndex.push_back(ri);
            }
            else
            {
                m_jpiIndex.m_vectDiscreteIndex.push_back(std::stoi(st[j]));
            }
        }
    }
    else
    {
        if (StringUtil::String2Int(strIndex, iTmp))
        {
            m_jpiIndex.m_vectDiscreteIndex.push_back(iTmp);
        }
        else
        {
            zlog.SError("%s: tokenization index error: %s\n", __PRETTY_FUNCTION__, strIndex.c_str());
            return false;
        }
    }
    return true;
}

JsonPathFilterExpr JsonPathSquareBracket::GetAndDeleteJPFE(std::string strUUID)
{
    for (auto it = m_vecFilterExpr.begin(); it != m_vecFilterExpr.end(); it++)
    {
        if (it->m_strUUID == strUUID)
        {
            JsonPathFilterExpr jpfe = *it;
            m_vecFilterExpr.erase(it);
            return jpfe;
        }
    }
    return JsonPathFilterExpr();
}
